<template>
  <div>
    <component
      v-for="control in controls"
      :is="control.RenderComponent"
      :key="control.key"
      :item="control.item"
      :models="models"
      :readonly="formReadOnly"
      :datas="datas"
      :formDataChange="formDataChange"
      :options="options"
      :flowInfo="flowInfo"
      :flowConfig="flowConfig"
      :defKey="defKey"
      :taskId="taskId"
      :appName="appName"
      :formUrl="formUrl"
      :defid="defid"
      :showNextNode="showNextNode"
      :showNextAssignees="showNextAssignees"
      :oneLegKicking="oneLegKicking"
      :multiple = "multiple"
      :defaultCustom = "defaultCustom"
      @change="change"
      @sublist-change="onListChange"
      @form-change="onFormChange"
      @global-event="onGlobalEvent"
      @comment-change="commentChange"
      ref='itemRefs'
    />
  </div>
</template>

<script>
import cloneDeep from 'lodash.clonedeep'
import { recalculate, isSame } from 'utils'
import { validator } from '../../utils/business-validator'
import { getControl } from '../../controls'

export default {
  props: {
    pageConfig: {
      type: Object,
      default: () => ({
        "children": [],
        "config": {
          "labelWidth": 100,
          "labelPosition": "right",
          "size": "small"
        }
      })
    },
    models: Object,
    datas: Object,
    options: Object,
    flowInfo: Object,
    flowConfig: Object,
    defKey: String,
    taskId: String,
    defid: String,
    appName: Object,
    formDataChange: Object,
    formReadOnly: Boolean,
    showNextNode: Boolean,
    showNextAssignees: Boolean,
    oneLegKicking: Boolean,
    formUrl: String,
    multiple: Boolean,
    defaultCustom: Boolean
  },
  data: () => ({
    hiddenControls: []
  }),
  computed: {
    controls () {
      let { hiddenControls } = this
      let { children } = this.pageConfig
      if (!children || children.length === 0) {
        return []
      }

      return children.filter(item => {
        return !hiddenControls.includes(item.key)
      }).map(item => ({
        key: item.key,
        item,
        RenderComponent: getControl(item.type)
      }))
    }
  },
  methods: {
    change(e, value) {
      if(!e){
        this.$emit("change", value, "initData")
      }else{
        this.$emit("change", this.getValue())
      }
    },
    businessValidator() {
      const formData = this.getValue()
      let sameFormExt =  (this.models && this.models.sameFormExt) || {}
      return validator(formData, sameFormExt, this.models, true)
    },
    recalculate (ctypes) {
      Vue.nextTick(() => {
        const oldData = this.getValue() //Object.assign({}, this.getValue(), val)
        const newData = recalculate(oldData, this.models && this.models.meta)
        // console.log('on recalculate change', oldData, newData)
        if (!isSame(oldData, newData)) {
          this.$refs.itemRefs && this.$refs.itemRefs.forEach(vm => {
            // console.log('list change', vm)
            if (ctypes.indexOf(vm.item && vm.item.type) > -1) {
              // console.log('set value', newData)
              vm.setValue(newData)
            }
            // if (item.getValue) {
            //   const itemValue = item.getValue()
            //   Object.assign(value, cloneDeep(itemValue))
            // }
          })
        }
      })
    },
    onFormChange (event) {
      this.recalculate(['sub-form'])
      this.$emit("subform-change", event, this.getValue())
    },
    onGlobalEvent (modelKey, isVisible) {
      const { hiddenControls } = this

      if (!isVisible && !hiddenControls.includes(modelKey)) {
        hiddenControls.push(modelKey)
      }

      if (isVisible && hiddenControls.includes(modelKey)) {
        for (let i = hiddenControls.length; i >=0; i--) {
          if (hiddenControls[i] === modelKey) {
            hiddenControls.splice(i, 1)
          }
        }
      }
    },
    onListChange (data, e, tableMeta) {
      if(!e){
        return
      }
      this.$emit("subgrid-change", e, tableMeta, this.getValue())
      this.recalculate(['sub-form', 'sub-grid'])
    },
    commentChange (obj, nextFlag) {
      this.$emit("commentp-change", obj, nextFlag, this.getValue())
    },
    getValue () {
      let value = {}
      this.$refs.itemRefs && this.$refs.itemRefs.forEach(item => {
        if (item.getValue) {
          const itemValue = item.getValue()
          Object.assign(value, cloneDeep(itemValue))
        }
      })

      return value
    },
    setValue (val) {
      this.$refs.itemRefs && this.$refs.itemRefs.forEach(item => {
        if (item.setValue) {
          // item.setValue(val)
          item.setValue(recalculate(val, this.models && this.models.meta))
        }
      })
    },
    validate (options) {
      const { itemRefs } = this.$refs
      if (!itemRefs) {
        return true
      }
      // 特殊处理：针对toolbar按钮操作，如果发现itemRefs中包含下一步组件实例，那么该实例只在按钮类型为“start”、“submit”进行校验；
      const toolbar = options && options.$toolbar;
      let ret = true
      itemRefs.forEach(item => {
        let elClassName = item.$el.className;
        if(/emap-flow-next-step/.test(elClassName) && toolbar) {
          if ((toolbar.id === "start" || toolbar.id === "submit") && item.validate && item.validate() === false) ret = false
        }else{
          if (item.validate && item.validate() === false) ret = false
        }
      })
      return ret
    },
    refresh (data) {
      this.$refs.itemRefs && this.$refs.itemRefs.forEach(item => {
        if (item.refresh) {
          item.refresh(data)
        }
      })
    }
  }
}
</script>
